Partially initializing object attributes using functools.partial in python [closed] - python

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 months ago.
Improve this question
I'm wondering whether it is a valid use case of functools.partial to partially initialize object attributes in python. Let's say I have some base class A that has three object-level attributes (attr1, attr2, attr3):
class A:
def __init__(self, attr1, attr2, attr3):
self.attr1 = attr1
self.attr2 = attr2
self.attr3 = attr3
def do_something(self):
pass
Now I want to create objects based on this base class for which one of the attributes (say attr1) is always fixed, but the other two may vary. One way I can think of doing this is to define a class that inherits from base class A and has a fixed class-level attribute which is used during initialization, something like this:
class PartialA(A):
attr1="foo" # fixed class-level attribute
def __init__(self, attr2, attr3):
super().__init__(self.attr1, attr2, attr3)
I can then create objects by specifying only the varying object-level attributes, like so:
partial_a = PartialA(attr2="baz", attr3="baz")
Another way to achieve a similar behavior would be to use functools.partial to partially initialize the __init__ of the base class A and then create objects off of it:
from functools import partial
PartialA = partial(A, attr1="foo")
partial_a = PartialA(attr2="bar", attr3="baz")
Are both approaches equally valid, or are there dangers/drawbacks to the approach using functools.partial in this way that I am currently not aware of? Would be happy to hear your opinions!
I tried both of the approaches outlined above and so far, I can not really see any difference in terms of behavior. But there might well be some reasons to favor one over another that I'm currently unaware of.

In both cases, you are basically defining factory functions to create instances of A. I would take a third route, an alternate constructor implemented using a class method.
class A:
def __init__(self, attr1, attr2, attr3):
self.attr1 = attr1
self.attr2 = attr2
self.attr3 = attr3
#classmethod
def with_foo(cls, attr2, attr3):
return cls("foo", attr2, attr3)
def do_something(self):
pass
a = A.with_foo("bar", "baz") # a = A("foo", "bar", "baz")
One major difference between this and your two attempts is that you can't override how A.with_foo sets the first attribute. (With the class, you can simply redefine PartialA.attr1 before creating an instance, plus you now have a weird second class that doesn't need to exist. With partial, you can still pass your own value of attr1 as a keyword argument.)

Related

Python - init argument not used in self [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 months ago.
Improve this question
I came by a code and wanted to get more understanding on when to use such arrangement.
What would be a good scenario of not using __init__'s argument (name) in self?
class ArgumentNotUsedInSelf:
def __init__(self, name: str):
self.type = "user"
user_one = ArgumentNotUsedInSelf("Mike")
print(user_one.type)
Any explanations from architectural (and not only) point of view are most welcome!
Some of the reasons for this can be:
Historical. The class used to use the argument, but it was changed so it's no longer meaningful. The argument was kept for backward compatibility.
Class hierarchy. This may be a child class of a class that uses the argument, but the child overrides the need for it. The argument is required for compatibility with the parent.
Sort of Barmar's historical example... let's say:
ArgumentNotUsedInSelf used to do something with name, but now doesn't.
But name is still used in SubClass, and changing everything could mess up dependent programs.
class ArgumentNotUsedInSelf:
def __init__(self, name: str):
self.type = "user"
class SubClass(ArgumentNotUsedInSelf):
def __init__(self, name):
super(SubClass, self).__init__(name)
self.name = name
x = SubClass('Mike')
print(x.name, x.type)
Output:
Mike user
This would be helpful if you want to store the field "name" of the created object and re-use it later:
class ArgumentNotUsedInSelf:
def __init__(self, name: str):
self.type = "user"
self.name = name
user_one = ArgumentNotUsedInSelf("Mike")
print(user_one.type)
print(user_one.name)

Explanation of 'list' and 'object' as parameter in class definition [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Can somebody please explain what is the purpose of 'object' and 'list' parameters in the classes Card and StandardDeck? I find little information about this.
Phycharm says this about 'object' in class Card():
The base class of the class hierarchy.
When called, it accepts no arguments and returns a new featureless instance that has no instance attributes and cannot be given any.
Is class card considered base class because of the 'object' parameter? Does the super().__init__() from class StandardDeck inherited from class Card? I really hope someone can give a good explanation i have been struggling for hours.
def main():
class Card(object):
def __init__(self, value, suit):
self.value = value
self.suit = suit
class StandardDeck(list):
def __init__(self):
super().__init__()
suits = list(range(4))
values = list(range(13))
[[self.append(Card(i, j)) for j in suits] for i in values]
deck = StandardDeck()
for card in deck:
print(card)
main()
object is the base class (also referred to a super class) for the derived class Card. This means Card inherit all the functionality and state of the base class (and as others said already this is implied anyhow), and it allows Card to override (or change) methods as needed. Another way to say that is Card is a more specialized class than object.
Similarly, list is the base class for StandardDeck.
I would also add that it's not a particular good design. For instance, list has a method called clear(). What does it mean to clear() a StandardDeck? It would be better design to use whatever data structures are needed an implementation detail (instance variables). This is sometimes expressed as failing the Liskov substitution principle (LSP).

Which of these is the best practice for accessing a variable in a class? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
If I have an object, and within that object I've defined a variable, which of these methods would be considered 'best' for accessing the variable?
Method One
Using a getter function
class MyClass:
def __init__(self):
self.the_variable = 21 * 2
def get_the_variable(self):
return self.the_variable
if __name__ == "__main__"
a = MyClass()
print(a.get_the_variable())
Method Two
Using the #property decorator
class MyClass:
def __init__(self):
self._the_variable = 21 * 2
#property
def the_variable(self):
return self._the_variable
if __name__ == "__main__"
a = MyClass()
print(a.the_variable)
Method Three
Simply accessing it directly
class MyClass:
def __init__(self):
self.the_variable = 21 * 2
if __name__ == "__main__"
a = MyClass()
print(a.the_variable)
Are any of these methods more pythonic than the others?
Method 3 is the standard pythonic way to start. If you need additional logic, filtering or some other behavior for the attribute you can always go back and add a method for the attribute and use the #property decorator at a later time. That's the beauty of python, start with something simple that works. If you later need finer control over the attribute you can create the property and not have to update/change any of the client code that uses the attribute. The client code will not know the difference between accessing the attribute directly vs calling a method and as a result does not have to change.
This ideology is confirmed via PEP 549
Python's descriptor protocol guides programmers towards elegant API design. If your class supports a data-like member, and you might someday need to run code when changing the member's value, you're encouraged to simply declare it as a simple data member of the class for now. If in the future you do need to run code, you can change it to a "property", and happily the API doesn't change.
I think it's not easy to answer since it's based on the program.
class MyClass:
def __init__(self):
self.the_variable = 21 * 2
def get_the_variable(self):
return self.the_variable
But if you want to pass a class attirubete to some variable, I think it's better to use getter-setter, since it is more readable and understandable. Because you are basically telling I ask this value. For example:
if __name__ == "__main__":
a = MyClass()
modified_variable = a.get_the_variable() * 2
In contrary, if you are just using that class attribute, third option a.the_variable is better.
if a.get_the_variable() == 42:
# do something
else:
# do something

Nested classes for cleaner inheritance? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
Say I have a class BigObject, which contains within it a number of SmallObjects - and this is the only place where SmallObject is used.
class SmallObject:
pass
class BigObject:
def __init__(self):
self.objects = [SmallObject() for _ in range(10)]
This is all fine, until I want a second version of these two, which inherits some behaviour and overrides some; inheritance seems natural, except:
class NewSmallObject(SmallObject):
pass
class NewBigObject(BigObject):
def __init__(self):
super().__init__()
self.objects = [NewSmallObject for _ in range(10)]
We had to create a bunch of SmallObjects only to immediately override them with NewSmallObjects. Which is not great if e.g. SmallObjects are expensive to create. Also, if we change how the list of SmallObjects is created in BigObject, those changes don't get passed on to NewBigObject.
The solution I came up with was to use nested classes:
class BigObject:
class SmallObject:
pass
def __init__(self):
self.objects = [self.SmallObject() for _ in range(10)]
class NewBigObject(BigObject):
class SmallObject(BigObject.SmallObject):
pass
This deals with both the issues described above. My main concern is that when I looked on StackOverflow for questions about nested classes in Python people keep saying nested classes are unpythonic, and I'd like to understand why. It can also create quite deeply nested classes if SmallObject contains TinyObjects which contain MinisculeObjects etc, which may be the answer?
So my question is basically:
is this a "good" solution to this problem?
if not, what would a good alternative be?
The solution is, as you've already found, to make SmallObject an attribute of the BigObject class.
There is nothing inherently wrong with using a nested class for this, but the readability of your code may suffer if the nested class is very long. Generally speaking, I would recommend to define SmallObject in the global scope though. After all, the Zen of Python says "Flat is better than nested". If you keep nesting TinyObjects and MinisculeObjects, your code will quickly become unreadable:
class BigObject:
class SmallObject:
class TinyObject:
class MinisculeObject:
... # MinisculeObject class body
... # TinyObject class body
... # SmallObject class body
... # BigObject class body
Defining your classes in the global scope only requires minimal extra effort, and looks much cleaner:
class MinisculeObject:
... # MinisculeObject class body
class TinyObject:
miniscule_object_factory = MinisculeObject
... # TinyObject class body
class SmallObject:
tiny_object_factory = TinyObject
... # SmallObject class body
class BigObject:
small_object_factory = SmallObject
... # BigObject class body
This looks like a good use case for the Abstract Factory pattern.
The gist is that there is a class hierarchy for creating things that derive from SmallObject. That way subclasses of BigObject will all use the same interface to get their SmallObject instances.

Passing variables, creating instances, self, The mechanics and usage of classes: need explanation [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I just rewrote a working program into functions in a class and everything messed up.
First, in the __init__ section of the class I declared a bunch of variables with self.variable=something.
Should I be able to access/modify these variables in every function of the class by using self.variable in that function? In other words, by declaring self.variable I have made these variables, global variables in the scope of the class right?
If not, how do I handle self?
Second, how do I correctly pass arguments to the class?
Third, how do I call a function of the class outside of the class scope?
Fouth, how do I create an Instance of the class INITIALCLASS in another class OTHERCLASS, passing variables from OTHERCLASS to INITIALCLASS?
I want to call a function from OTHERCLASS with arguments from INITIALCLASS. What I've done so far is.
class OTHERCLASS():
def __init__(self,variable1,variable2,variable3):
self.variable1=variable1
self.variable2=variable2
self.variable3=variable3
def someotherfunction(self):
something=somecode(using self.variable3)
self.variable2.append(something)
print self.variable2
def somemorefunctions(self):
self.variable2.append(variable1)
class INITIALCLASS():
def __init__(self):
self.variable1=value1
self.variable2=[]
self.variable3=''
self.DoIt=OTHERCLASS(variable1,variable2,variable3)
def somefunction(self):
variable3=Somecode
#tried this
self.DoIt.someotherfunctions()
#and this
DoIt.someotherfunctions()
I clearly didn't understand how to pass variables to classes or how to handle self, when to use it and when not. I probably also didn't understand how to properly create an instance of a class. In general I didn't understand the mechanics of classes so please help me and explain it to me like I have no idea (which I don't, it seems). Or point me to a thorough video, or readable tutorial.
All I find on the web is super simple examples, that didn't help me much. Or just very short definitions of classes and class methods instances etc.
I can send you my original code if you guys want, but its quite long.
class Foo (object):
# ^class name #^ inherits from object
bar = "Bar" #Class attribute.
def __init__(self):
# #^ The first variable is the class instance in methods.
# # This is called "self" by convention, but could be any name you want.
#^ double underscore (dunder) methods are usually special. This one
# gets called immediately after a new instance is created.
self.variable = "Foo" #instance attribute.
print self.variable, self.bar #<---self.bar references class attribute
self.bar = " Bar is now Baz" #<---self.bar is now an instance attribute
print self.variable, self.bar
def method(self, arg1, arg2):
#This method has arguments. You would call it like this: instance.method(1, 2)
print "in method (args):", arg1, arg2
print "in method (attributes):", self.variable, self.bar
a = Foo() # this calls __init__ (indirectly), output:
# Foo bar
# Foo Bar is now Baz
print a.variable # Foo
a.variable = "bar"
a.method(1, 2) # output:
# in method (args): 1 2
# in method (attributes): bar Bar is now Baz
Foo.method(a, 1, 2) #<--- Same as a.method(1, 2). This makes it a little more explicit what the argument "self" actually is.
class Bar(object):
def __init__(self, arg):
self.arg = arg
self.Foo = Foo()
b = Bar(a)
b.arg.variable = "something"
print a.variable # something
print b.Foo.variable # Foo
So here is a simple example of how to use classes:
Suppose you are a finance institute. You want your customer's accounts to be managed by a computer. So you need to model those accounts. That is where classes come in. Working with classes is called object oriented programming. With classes you model real world objects in your computer. So, what do we need to model a simple bank account? We need a variable that saves the balance and one that saves the customers name. Additionally, some methods to in- and decrease the balance. That could look like:
class bankaccount():
def __init__(self, name, money):
self.name = name
self.money = money
def earn_money(self, amount):
self.money += amount
def withdraw_money(self, amount):
self.money -= amount
def show_balance(self):
print self.money
Now you have an abstract model of a simple account and its mechanism.
The def __init__(self, name, money) is the classes' constructor. It builds up the object in memory. If you now want to open a new account you have to make an instance of your class. In order to do that, you have to call the constructor and pass the needed parameters. In Python a constructor is called by the classes's name:
spidermans_account = bankaccount("SpiderMan", 1000)
If Spiderman wants to buy M.J. a new ring he has to withdraw some money. He would call the withdraw method on his account:
spidermans_account.withdraw_money(100)
If he wants to see the balance he calls:
spidermans_account.show_balance()
The whole thing about classes is to model objects, their attributes and mechanisms. To create an object, instantiate it like in the example. Values are passed to classes with getter and setter methods like `earn_money()ยด. Those methods access your objects variables. If you want your class to store another object you have to define a variable for that object in the constructor.
The whole point of a class is that you create an instance, and that instance encapsulates a set of data. So it's wrong to say that your variables are global within the scope of the class: say rather that an instance holds attributes, and that instance can refer to its own attributes in any of its code (via self.whatever). Similarly, any other code given an instance can use that instance to access the instance's attributes - ie instance.whatever.

Categories

Resources