Intern study summary - Jun 13 Tue
Python
pass
In Python, the pass
keyword is a
placeholder statement. It is used when a statement is
required syntactically, but no action needs to be performed.
Example.
Suppose you're designing a new class and you know it needs a
particular method, but you aren't sure what the implementation of that
method should be yet. You can use pass
as a placeholder
like so:
1 |
|
In this code, future_method
does nothing, but it's a
valid method. Without the pass
statement, the code would
have a syntax error because Python expects a block of code to follow the
method definition. The pass
keyword is saying, "I
acknowledge that you expect something here, but I don't want to do
anything."
Similarly, it can be used in conditional statements, loops, etc. where some code is expected:
1 |
|
In the above case, pass
is used to indicate that this
condition should be handled in the future.
Keep in mind, it's typically used in development phases, and in most
cases, you should eventually replace pass
with some
meaningful code.
@dataclass
The @dataclass
decorator is a feature of Python
introduced in Python 3.7, as part of the dataclasses
module. It provides a convenient way to generate special methods for
classes which mainly contain data, like the init,
repr, and eq methods.
Example:
1 |
|
DogInfo
is defined as a dataclass, which means Python
will automatically add special methods like init,
repr, and eq.
Compare to Java
Java does not have a direct equivalent to Python's dataclasses, but it does have similar features for creating simple classes that mainly contain data.
One approach in Java is to create a simple class with private fields,
and generate getter, setter, equals()
,
hashCode()
, and toString()
methods. Most
modern Java IDEs can generate these methods for you.
Starting from Java 14, there's also a preview feature called
record
which provides similar functionality to Python's
dataclasses. Here's an example:
1 |
|
In this Java code, DogInfo
is defined as a record with
two fields: name
and age
. Java automatically
generates constructor, equals, hashCode, and toString methods.
@dataclass(frozen=True)
the (frozen=True)
The @dataclass
decorator in Python comes with several
parameters that you can use to customize the behavior of the dataclass,
and one of these parameters is frozen
.
If you set frozen=True
when you define a dataclass, it
makes the instances of that dataclass immutable, similar to a tuple.
That is, once the instance has been created and its attributes have been
set, you can't change them.
If you try to change an attribute of a frozen dataclass, Python raises an exception. Here's an example:
1 |
|
If you run this code, you'll get a FrozenInstanceError
when you try to assign 5
to p.x
.
The frozen=True
parameter is useful when you want to
create a dataclass that is hashable and can be used as a dictionary key,
or when you want to ensure that an instance of the class won't change
once it's been created.
Compare to Java’s
final
keyword
Compare with final float PI
in Java: the
frozen=True
parameter for Python's @dataclass
and the final
keyword in Java serve similar purposes, but
they're not exactly the same.
The frozen=True
parameter in Python makes it so that all
attributes of an instance of a dataclass are immutable -- you can't
change them once they're set. This is similar to how a
final
variable in Java can't be changed once it's
initialized.
However, the final
keyword in Java can be used in
several contexts. When used with a variable (like
final float PI
), it makes that variable a constant -- you
can't change its value once it's initialized. When used with a class, it
means the class can't be subclassed. When used with a method, it means
the method can't be overridden by subclasses.
The frozen=True
parameter in Python's
@dataclass
only affects the mutability of instances of the
class. It doesn't prevent the class from being subclassed, nor does it
prevent methods from being overridden. There's no exact equivalent in
Python for Java's final
keyword when used with classes and
methods. Python's philosophy tends towards allowing greater flexibility,
so "final" classes and methods are not a language feature.
post_init
The __post_init__
method in Python is a special method
provided by the dataclasses module. It's a method that you can define in
your dataclass, and if it exists, it gets called automatically at the
end of the generated __init__
method.
The purpose of the __post_init__
method is to perform
any additional initialization steps that you need to do beyond just
setting the attributes of your dataclass to the provided values.
Here's an example of how you might use it:
1 |
|
In this example, after the x
and y
attributes are set in the __init__
method, the
__post_init__
method is automatically called. This
calculates the magnitude of the point from its x
and
y
coordinates and stores it in the magnitude
attribute.
If you don't define a __post_init__
method in your
dataclass, then nothing extra happens after __init__
. But
if you do define it, then it provides a way to add some additional
initialization behavior that goes beyond just setting attribute
values.
Inherit in Python and Java
Inheritance is a key feature in many object-oriented programming languages, including Python and Java. It is a mechanism that allows a class to acquire the properties and behaviors of another class.
The class from which properties are inherited is known as the parent class, superclass, or base class. The class that inherits those properties is known as the child class, subclass, or derived class.
When a class inherits from another class in Python, it gains access to all of the superclass's attributes and methods. This means that objects of the subclass can be treated as instances of the superclass, and code that works with the superclass will automatically work with the subclass.
Python's inheritance is defined as follows:
1 |
|
In this example, ChildClass
is inheriting from
ParentClass
.
Python supports both single and multiple inheritance. Single inheritance is when a class inherits from a single superclass, while multiple inheritance is when a class inherits from more than one superclass. Here is an example of multiple inheritance:
1 |
|
In this example, ChildClass
is inheriting from both
ParentClass1
and ParentClass2
.
Java also supports inheritance, but with a key difference: Java does not support multiple inheritance for classes. A class in Java can only directly inherit from one superclass. However, a class can implement multiple interfaces, which is a sort of workaround for multiple inheritance.
This is how you define inheritance in Java:
1 |
|
In this example, ChildClass
is inheriting from
ParentClass
.
Despite the difference in multiple inheritance, the fundamental idea behind inheritance is the same in both languages. It's a way to organize code, increase reusability, and set up relationships between different types.
Also, Java have abstract class which might be different with what python’s inherit behaves.
A key example:
Yes, you're correct. When you create an instance of
AClass
by calling AClass("t1", "t2", "t3")
,
the p1
, p2
, and p3
attributes of
a_class
will be set to "t1", "t2", and "t3"
respectively.
The values "p1_attribute", "p2_attribute", and "p3_attribute" specified in the class definition are default values. They are used if you create an instance without providing corresponding arguments.
Here's how it works:
Try to answer the following question:
If I have code
1 |
|
and I have a_class = AClass("t1", "t2", "t3")
, then the
p1, p2, p3
of a_class
will be "t1", "t2", and
"t3"?
yield
I search several times on the yiedl
key word in python.
Even with ChatGPT, I cannot clearly understand how yield
keyword is working in python and why we need it. One key step to
understand it is that the yield
keyword
cannot be replaced with return
because
return
in a function terminates the
function entirely, while yield
only pauses
the function. If you replace yield
with
return
, your function will stop executing
after the first return
statement it
encounters, and it will not be able to produce multiple values over
time.
The yield
keyword in Python is used in a special kind of
function called a generator. Generators are a type of iterable, like
lists or tuples. Unlike lists, they don't allow indexing with arbitrary
indices, but they can still be iterated through with for loops.
When the yield
keyword is called in a function, it
returns a value and pauses execution of the function. The function can
then be resumed right where it left off, allowing it to generate a
sequence of results over time, instead of computing them all at once and
returning them in a list for instance.
Here's a simple example:
1 |
|
This will output:
1 |
|
If you only need to generate a single value from your function, then
you can use return
instead of yield
. Also, if
your function generates a small number of values, you might be able to
use return
to return them all at once in a list, rather
than generating them one at a time with yield
.
In summary, yield
is a special keyword used in the
context of Python generators, and it cannot be simply replaced with
return
without changing the function's behavior.
Can I use a block
of code to implement yield
?
In Python, the yield
keyword is used to make a function
into a generator that can produce a sequence of results over time.
However, the yield
keyword itself does quite a bit of
behind-the-scenes work, so it's not straightforward to replace it with a
few lines of code. You would need to implement a whole class with an
iterator to get equivalent behavior.
Here is a simple example of how you might do that. This example implements a generator that yields the numbers 1, 2, and 3, similar to the previous example.
1 |
|
In this code, the SimpleGenerator
class has a
__next__
method that implements the logic of the generator:
it keeps track of the current number, and each time
__next__
is called, it increments the number and returns
it. When the number gets bigger than 3, it raises a
StopIteration
exception, which signals that the generator
is done.
This is a more explicit way of implementing a generator, and it can
give you a clearer sense of what's going on behind the scenes when you
use the yield
keyword. However, using yield
is
generally simpler and more concise, which is why it's usually preferred
for creating generators in Python.
but
with yield
keyword, there won't be such thing to store the
iterable result, which means I won't be able to print the whole return
result inside of the method with 'yield`?
enumerate()
The enumerate
function in Python is a built-in function
that allows you to loop over something and have an automatic
counter.
In a for
loop, when you use
enumerate(sources)
, it returns an enumerate object, which
is an iterable that yields pairs of the form
(index, value)
. In each iteration of the loop,
idx
is the index of the current item, and
source
is the value of the current item.
Here's a simple example:
1 |
|
This will output:
1 |
|
As you can see, idx
is the index of each item in the
list, and fruit
is the value of each item. This can be very
useful in situations where you need to know the index of the items as
you're looping over them.
iter()
The iter()
function in Python is a built-in function
that returns an iterator object. An iterator is an object that can be
iterated (looped) upon. An object which will return data, one element at
a time when next()
is called on it.
In more technical terms, an iterator is an object that implements the
iterator protocol, which consists of the methods __iter__()
and __next__()
.
Here's an example:
1 |
|
In this code, iter(my_list)
returns an iterator object
that you can fetch values from one at a time using the
next()
function. Once all elements are exhausted,
next()
will raise a StopIteration
exception.
Most of the time, you don't need to use iter()
and
next()
directly, because Python's for
loop
automatically calls them when you loop over an iterable object:
1 |
|
This code does the same thing as the previous example, but it's a lot
simpler and clearer. The for
loop automatically calls
iter(my_list)
to get an iterator, and then it calls
next()
on that iterator for each iteration of the loop.
When next()
raises a StopIteration
exception,
the for
loop catches it and gracefully exits the loop.
ternary operator in Python
Example:
rewrite the following Java code in Python
1 |
|
Python does have a similar construct, but the syntax is different
from Java. Instead of (j > 1) ? 6 : 7
, in Python you
would write 6 if j > 1 else 7
.
Here's an example:
1 |
|
In this Python code, 6 if j > 1 else 7
is a
conditional expression (often called a ternary operation). It checks if
j > 1
. If j > 1
is true, it evaluates to
6
. Otherwise, it evaluates to 7
. This value is
then assigned to i
.
This is similar to the ? :
operator in Java, but the
syntax is slightly different.
Git
Differences
between git switch another-branch
and
git checkout another-branch
In versions of Git prior to 2.23, the command
git checkout
was primarily used to switch between branches
in a Git repository. However, starting from Git 2.23, the command
git switch
was introduced as a more intuitive and safer
alternative to git checkout
when it comes to switching
branches. Here are the main differences between the two commands:
- Simplicity and clarity: The
git switch
command was introduced to provide a clearer and more straightforward syntax for switching branches. The name "switch" better reflects the action being performed, making it easier to understand its purpose at a glance. - Safety: The
git switch
command is designed to be more cautious and less error-prone thangit checkout
. When usinggit switch
, Git performs additional checks to ensure that you don't accidentally lose work or overwrite uncommitted changes. For example, if you have uncommitted changes in your working directory, Git will refuse to switch branches unless you either commit the changes or stash them. This helps prevent data loss. - Branch creation: With
git switch
, you can create and switch to a new branch in a single command using thegit switch -c <new-branch>
syntax. This combines the creation of a branch and switching to it into a single step. In contrast,git checkout
requires separate commands to create and switch to a new branch (git branch <new-branch>
andgit checkout <new-branch>
). - Replacing detached HEAD: In
git switch
, the commandgit switch <commit>
is used to switch to a specific commit, effectively replacing the old "detached HEAD" state. This syntax makes it more explicit and less error-prone to switch to a specific commit, as opposed togit checkout <commit>
.
It's worth noting that git checkout
is still supported
in recent versions of Git to maintain backward compatibility, but
git switch
is encouraged for branch switching operations
due to its advantages in safety and simplicity.
Git command for create and checkout to a new branch together
You may use git checkout -b another-branch
Terminal Command
Split the command window to multiple sub windows
You may use command
+ D
on key board