Static variable vs class variable vs instance variable vs local variable - oop

Before posting, I read more than a half dozen posts in a search from this site (python variables class static instance local)
https://stackoverflow.com/search?q=python+variables+class+static+instance+local
I bookmarked several of the results for future studying, but none of them seemed to clarify to me if my thinking is right or wrong, so I feel I may be missing something about the basics (see below)...
Are the terms 'class variable' and 'static variable' referring to the same thing? After about three Google searches, reading through ~6 articles per search that I could understand, I've reached a conclusion that class and static variables are the same thing. But, since I'm just learning the fundamentals of Python and OOP, this conclusion may be wrong so I want to find any flaws in my reasoning before I continue learning with the wrong mindset. In the code below:
class Variables():
scVar = 3
def __init__(self, a, b):
self.iVar1 = a
self.iVar2 = b
def getLocalVar3(self):
localVar1 = 17
localVar2 = 100
localVar3 = localVar1 + localVar2
return localVar3
Is 'scVar' both a class variable and a static variable ('class' and 'static' variables being synonymns)?
The second question is to clarify my understanding of differentiating class variables, instance variables, and local variables. In the code above, I'm thinking that scVar is a class variable; iVar1 and iVar2 are instance variables; and localVar1, localVar2, and localVar3 are local variables. Is that correct to say, or is there something that I'm missing?
Thanks cirosantilli, That article that you linked to is one I haven't seen yet. I'm going to look that over. I wonder a bit about Python's point of vew that there's not a distinction between class variables and instance variables. Is this point of view one that I should try to understand correctly right up front, as a beginner, or should I just keep the idea in mind and not worry too much about reconciling my current point of view with that one until I become more experienced? That question probably seems overly vague, and dependent upon my current level of understanding Python. Mostly, I've been running commands on class examples similar to what is in the original post; predicting the output before I press the [enter] key and then studying the output when it's not what I predicted. From that, I'm starting to get some grasp of how things work in Python. Basically, I've just recently started getting a glimpse of how OO works in Python - inching forward, slowly but surely.
"However the above are just conventions: from the language point of view there is no distinction between class variables and instance variables." -- Just to help me understand this better, does the part, 'from the language point of view ...' sort of imply that the Python documentation explains this point of view somewhere within it? If so, I'll re-read through the docs and look specifically for this part, and try to conform my thinking process to it. "... between class variables and instance variables." So, even though there's the difference in the way that class and instance variables can be seen and accessed by 'classobj's and 'instance's, Python's
point of view is that there is no distinction between them? I'm going to keep this idea in mind during future reading so that I can maybe get rid of some confusion on my part. After I run the *.py in the original post, I get the following outputs in IDLE, using Python 2.7.x (only the last line of the traceback error is included, for better readability):
>>> Variables.scVar
3
>>> Variables.iVar1
AttributeError: class Variables has no attribute 'iVar1'
>>> instance = Variables(5, 15)
>>> instance
<__main__.Variables instance at 0x02A0F4E0>
>>> Variables
<class __main__.Variables at 0x02A0D650>
>>> instance.scVar
3
>>> instance.iVar1
5
>>> instance2 = Variables(25, 35)
>>> instance2.scVar
3
>>> Variables.scVar = Variables.scVar * 100
>>> Variables.scVar
300
>>> instance.scVar
300
>>> instance2.scVar
300
>>> instance.scVar = 9999
>>> Variables.scVar
300
>>> instance.scVar
9999
>>> instance2.scVar
300
>>> type(Variables)
<type 'classobj'>
>>> type(instance)
<type 'instance'>
"However the above are just conventions: from the language point of view there is no distinction between class variables and instance variables." -- By using the code from the original post, is there maybe a sequence of commands that illustrates this point? I don't doubt that you know what you're talking about; I just find it difficult to reconcile my current way of thinking with the above statement. But I get the feeling that if I can start to see the difference between the two perspectives, that something important will 'click'.
As an afterthought to the last few sentences, I might be on to seeing things more along the same lines as your statement about 'no distinction between class variables and instance variables', but only if my following assumption is accurate... From the code in the original post (class Variables - 12 lines), are there just the two scopes of global and local involved in that program? Since I've just started to form conclusions about how it all fits together, I think that my limited understanding of scope might be what keeps me from fully grasping the idea that there's no distinction between class variables and instance variables. The only thing I can seem to make of it now is that (only maybe) - 'Python has no distinction between class variables and instance variables; but the differences between global and local scope might make it appear to a novice that there is a distinction between these two types of variables. I don't know, does that statement identify a potential 'hang up' that I could be having about it?
"Everything is an object, including classes and integers:" -- I've read this numerous times. So much so that I take it to be a core belief to understanding OO and Python, but it's not a concept in which I fully realize the implications of yet (I think).
class Foo():
integer = 10
float = 6.37
string = 'hello'
boolean = True
idkyet = None
def __init__(self):
self.a = 'iv_a'
self.b = 'iv_b'
self.c = 'iv_c'
def Func(self):
self.g = 'g'
h = 'h'
i = 'i'
return 'g' + 'h' + 'i'
>>> Foo
<class __main__.Foo at 0x02A1D650>
>>> type(Foo.integer)
<type 'int'>
>>> type(Foo.float)
<type 'float'>
>>> type(Foo.string)
<type 'str'>
>>> type(Foo.boolean)
<type 'bool'>
>>> type(Foo.idkyet)
<type 'NoneType'>
>>> type(Foo)
<type 'classobj'>
>>> import os
>>> type(os.getcwd() + '\\Test.py')
<type 'str'>
>>> type(os)
<type 'module'>
>>> f = Foo()
>>> type(f)
<type 'instance'>
>>> type(f.Func)
<type 'instancemethod'>
>>> type(f.Func())
<type 'str'>
>>> f.Func
<bound method Foo.Func of <__main__.Foo instance at 0x02A25AF8>>
>>> Foo.Func
<unbound method Foo.Func>
>>> type(f.a)
<type 'str'>
>>> type(Foo.a)
AttributeError: class Foo has no attribute 'a'
>>> type(Foo.self.a)
AttributeError: class Foo has no attribute 'self'
When I was about half way through this response, leaving off with the 'class Foo():' code above and the commands ran on it below that, I hit a snag and couldn't quite continue with the other follow-up question that I barely had in mind. So, I stepped away from the problem for awhile and started to read that 'cafepy...' link that you posted (by Shalabh Chaturvedi). That's really interesting. I had seen excerpts from that before but I hadn't read the whole thing, but it seems much more understandable now than it would have been just a week ago. I think I will read the whole thing. Don't mind the last half of this post (after the '***') because I still can't pinpoint exactly what I was trying to ask. ...everything is an object...mainly just a difference in object types???... < That is the note that I had jotted down when I almost had in mind how to frame the last question, but it never came to fruition. I'll have to wait until something else 'clicks' and I can see again what I had in mind.
I'll also keep in mind to stop and re-read if I glance across anything related to 'MRO', bound and unbound methods... I have been picking up just a bit of those three terms lately, in a way that it feels like they won't be too far in the future of my learning process.

I believe that static and class variables are commonly used as synonyms.
What you say about the variables is correct from the convention point of view: this is how you should think about them most of the time.
However the above are just conventions: from the language point of view there is no distinction between class variables and instance variables.
Python is not like C++ or Java.
Everything is an object, including classes and integers:
class C(object): pass
print id(C)
C.a = 1
assert C.__dict__['a'] == 1
There is no clear distinction between methods and instance variables: they are just attributes of an object.
Therefore, there is no language level distinction between instance variables and class variables: they are just attributes of different objects:
instance variables are attributes of the object (self)
class variables are attributes of the Class object.
The real magic happens on the order that the . operator searches for attributes:
__dict__ of the object
__dict__ of the class of the object
MRO up to parent classes
You should read this great article before you get confused in the future.
Also beware of bound vs unbound methods.
EDIT: attempt to address further questions by the OP made in his post.
Wow that was large! I'll try to read everything, but for the future you should try to keep questions more concice. More code, less talk =). You'll get better answers.
should I just keep the idea in mind and not worry too much about reconciling my current point of view with that one until I become more experienced?": I do things.
I do as I feel necessary. When necessity calls, or I can't take magic behaviour anymore, I learn.
sort of imply that the Python documentation explains this point of view somewhere within it?
I don't know about the docs, but the language itself works that way.
Of course, the language was designed to give the impression that syntax works just like in C++ in the common cases, and it adds a thin layer of magic to classes to make it look like so.
But, since that is not how it truly works, you cannot account for all (useful) behaviour by thinking only in terms of C++ class syntax.
By using the code from the original post, is there maybe a sequence of commands that illustrates this point?
I'm not sure it can be illustrated in sequence of commands. The point is: classes are objects, and their attributes are searched by the dot . MRO on the same order as attributes of objects:
class C(object):
i_static = 0
def __init__(self):
self.i = 1
# i is in the __dict__ of object c
c = C()
assert c.__dict__['i'] == 1
assert c.i == 1
# dot finds i_static because MRO looks at class
assert c.__class__.__dict__['i_static'] == 0
assert c.i_static == 0
# i_static is in the __dict__ of object C
assert C.__dict__['i_static'] == 0
assert C.i_static == 0
# __eq__ is in the dict of type, which is the __class__ of C
# By MRO, __eq__ is found. `C,C` because of bound vs unbound.
assert C.__class__.__dict__['__eq__'](C,C)
assert C == C
are there just the two scopes of global and local involved in that program?
This is a point I don't know very clearly.
There is a no global scope in Python, only module level.
Then there is a new local scope inside functions.
The rest is how the . looks for attributes.
can't pinpoint exactly what I was trying to ask
Ask: can I find a difference in syntax between classes, integers or functions?
If you think you have found one, ask: hmmm, how can I make an object with certain attributes that behaves just like that thing which does not look like an object?
You should find an answer every time.
Example:
def f(): pass
class C(object): pass
AHA: f is different than c = C() because I can do f() but notc()`!
But then, no, it is just that the f.__class__.__dict__['__call__'] attribute is defined for f, and can be found via MRO.
But we can do that for c too:
class C(object):
def __call__(self): pass
and now we can do c().
So they were not different in that aspect.

Related

Getting UndefVarError: new not defined when trying to define a struct with an inner constructor in Julia

I'm new to Julia and trying out some code I copied from this article. It's supposed to be a way to do object-oriented programming (i.e. classes) in Julia:
using Lathe.stats: mean, std
struct NormalDistribution{P}
mu::Float64
sigma::Float64
pdf::P
end
function NormalDistribution(x::Array)
pdf(xt::Array) = [i = (i-μ) / σ for i in xt]
return new{typeof(pdf)}(mean(x), std(x), pdf)
end
x = [5, 10, 15, 20]
dist = NormalDistribution(x)
However, when I run this with Julia 1.1.1 in a Jupiter notebook I get this exception:
UndefVarError: new not defined
Stacktrace:
[1] NormalDistribution(::Array{Int64,1}) at ./In[1]:11
[2] top-level scope at In[1]:15
I found this documentation page on inner constructor methods which explains that they have
a special locally existent function called new that creates objects of the block's type.
(although the documentation for new linked above says it is a keyword).
It's possible I may have copied the code incorrectly but maybe someone could explain how to implement what the original author was proposing in the article. Also, I don't know how to debug in Julia yet so any pointers appreciated.
What the documentation page you linked to means to say is that the new keyword only exists within inner constructors (as opposed to outer constructors).
So either you go for an outer constructor, in which case you want to use the default constructor in order to actually create your new instance:
using Statistics
# First the type declaration, which comes with a default constructor
struct NormalDistribution{P}
mu::Float64
sigma::Float64
pdf::P
end
# Another outer constructor
function NormalDistribution(x::Array)
μ = mean(x)
σ = std(x)
pdf(xt::Array) = [(i-μ) / σ for i in xt]
# This is a call to the constructor that was created for you by default
return NormalDistribution(μ, σ, pdf)
end
julia> x = [5, 10, 15, 20]
4-element Array{Int64,1}:
5
10
15
20
julia> dist = NormalDistribution(x)
NormalDistribution{var"#pdf#2"{Float64,Float64}}(12.5, 6.454972243679028, var"#pdf#2"{Float64,Float64}(12.5, 6.454972243679028))
julia> dist.pdf([1, 2, 3])
3-element Array{Float64,1}:
-1.781572339255412
-1.626653005407115
-1.4717336715588185
Note that the definition of pdf in the original article is obviously problematic (if only because μ and σ are not defined). I tried to modify it so that it makes some sense
One possible issue with this is that anyone can define a NormalDistribution instance with an inconsistent state:
julia> NormalDistribution(0., 1., x->x+1)
NormalDistribution{var"#11#12"}(0.0, 1.0, var"#11#12"())
Which is why you might want to actually define an inner constructor, in which case Julia does not provide you with a default constructor but you get access to that special new function which creates objects of the type you're defining:
# A type declaration with an inner constructor
struct NormalDistribution2{P}
mu::Float64
sigma::Float64
pdf::P
# The inner constructor is defined inside the type declaration block
function NormalDistribution2(x::Array)
μ = mean(x)
σ = std(x)
pdf(xt::Array) = [(i-μ) / σ for i in xt]
# Use the `new` function to actually create the object
return new{typeof(pdf)}(μ, σ, pdf)
end
end
It behaves exactly in the same way as the struct with an outer constructor, except this time no default constructor is provided anymore:
julia> dist2 = NormalDistribution2(x)
NormalDistribution2{var"#pdf#5"{Float64,Float64}}(12.5, 6.454972243679028, var"#pdf#5"{Float64,Float64}(12.5, 6.454972243679028))
julia> dist2.pdf([1, 2, 3])
3-element Array{Float64,1}:
-1.781572339255412
-1.626653005407115
-1.4717336715588185
# No default constructor provided
julia> NormalDistribution2(0., 1., x->x+1)
ERROR: MethodError: no method matching NormalDistribution2(::Float64, ::Float64, ::var"#9#10")
Stacktrace:
[1] top-level scope at REPL[13]:1
An inner constructor has to be defined inside of the struct definition body; this is the only place where new has any special meaning. Your constructor method is outside of the struct definition where new is just a regular (undefined) name.
Ok. Looks like you were very confused. So that function is meant to be included as an inner constructor to the outer constructor before the end. The problem is the code is divided and built upon slowly across the article where only parts of the whole constructor are shown. If you are interested, and like my blog, I am about to post a video on outer constructors and inner constructors on my channel, https://youtube.com/playlist?list=PLCXbkShHt01seTlnlVg6O7f6jKGTguFi7 , it will be part 9 ( I am editing it now,) maybe watching this in video form will make it make more sense.
enter image description here

Access to **private** variables of a class in Python

I understand that Python does not explicitly support private variables in a class. However, please consider the following program:
class AClass(object):
def __init__(self, x):
self.__x = x
class BClass(object):
def __init__(self, x):
self.__x = x
# _____________________________________________________________________________
aClass = AClass(10)
bClass = BClass(10)
aClass.__x = 15
print (aClass.__x)
##bClass.__x = 20
print (bClass.__x)
The program above, will produce following error:
AttributeError: 'BClass' object has no attribute '__x'
But, if the second last line of code is uncommented, it will execute without an error.
If someone can please clarify what appears to be an inconsistency and if there is a PEP that explains this behaviour, I would appreciate a pointer to it.
Best regards.
BD
It's because variables starting with a dunder are name mangled to "protect" them. If you examine the dictionary of bClass, you'll see:
>>> print(bClass.__dict__)
{'_BClass__x': 10, '__x': 20}
The _BClass__x (I'll call this the object variable) was created by the object itself, hence its mangled name. The __x was created outside of the class(a) which is why it has a non-mangled name, and therefore why you can access it with just __x.
To access the object variable for both types, you can use:
print (aClass._AClass__x)
print (bClass._BClass__x)
But I'm not sure how reliable that is. I am sure that it's something you probably shouldn't be doing however, since it breaks encapsulation :-)
In fact, though I said the mangling was done by the object, I want to make sure you understand it's not done when an object is instantiated. The actual mangling happens when the code is compiled, which you can see if you disassemble:
>>> import dis
>>> dis.dis(AClass)
Disassembly of __init__:
3 0 LOAD_FAST 1 (x)
2 LOAD_FAST 0 (self)
4 STORE_ATTR 0 (_AClass__x)
6 LOAD_CONST 0 (None)
8 RETURN_VALUE
The STORE_ATTR bytecode actually knows to use a mangled name.
(a) And it is very much distinct from the object variable, as you'll find to your distress when you later try to use __x within a member function and find it hasn't been changed by your code outside :-)

Coercion/type checking: manually reproduce Perl6 standards

I have a Module AttrX::Mooish which implements some of attribute features of Moo/Moose frameworks (lazyness, trigger, etc.). I also wanted the module to be as transparent to the end user as possible meaning support for both private and public attributes. It works by replacing attribute's container with a Proxy and storing its value in external storage. It also means that all the type checking and coercion Perl6 was doing is now my responsibility. My target is to mimic the default behavior is much as possible. I.e. for the end user:
has MyClass #foo is mooish(...);
must work the same as it would without the trait applied. Unfortunately, the subject of type manipulations is so much complicated and ununified in the language core that the more problems I fix the more problems I get afterwards. For example:
my Str #a = <a b c>; my Str #b = [1,2,3]
Type check failed in assignment to #b; expected Str but got Int (1)
As expected.
my Str #a; say #a.WHAT
(Array[Str])
Sure.
my Array[Str] $a = ["a", "b", "c"];
Type check failed in assignment to $a; expected Array[Str] but got Array ($["a", "b", "c"])
Well....
my Array[Str] $a = <a b c>;
Type check failed in assignment to $a; expected Array[Str] but got List ($("a", "b", "c"))
Not even coercing List to Array!
No wonder that the final typecheck line in my trait code:
$coerced-value ~~ $attr.type
Fails here and there despite same values/types used in variable/attribute assignments work OK.
I have a question with no hope of getting any positive answer to it: is there a single entry point used by the assignment operator which does all the coerce/typecheck? Ideally I would simply:
$value = coerce($value, $type);
check-type($value, :type($attr.type), :name($attr.name))
I tried to trace down from the grammar, but haven't got enough spare time to complete this yet. Besides, it is mostly nqp which I don't know and can't really understand.
But since the existence of such entry point(s) is unlikely I would like to ask for any advises related to this area. Like, for example, SmokeMachine on #perl6 provided me with a great idea of obtaining base type of a parametrized type using .^parents method.
So far, the biggest problems are with:
To check if type is parametrized I can't use a single role or class to match against. So far the only approach I have is by finding if there is of method and testing its output. Unfortunately, if a class provides FALLBACK very unclear error message (the one about AUTOGEN) is produced. :no_fallback is desirable, but definite and subset types have their own find_method which doesn't support named parameters and I end up with another error message.
If a prepare type-related attributes ($!coerce-type) in compose method of my trait role applied to the Attribute object (where actually the attributes are declared) I find them later at run-time unitialized. Guessing its something related to compose time. But wanna be sure if nothing is missed here.
Is there any better way to perform type-check than $value ~~ $type?
[Comments indicate that this out-of-date question was supposed to be closed in 2020 but it never was. Here's a very brief answer in case someone comes across this.]
Sometime after asking this question, the asker significantly revised Raku's coercion mechanism. See Report on New Coercions. This new syntax for coercion is in the docs.
Using this new style, the following line from the question:
my Array[Str] $a = ["a", "b", "c"];
say $a;
# OUTPUT: Type check failed in assignment to $a;
# expected Array[Str] but got Array ($["a", "b", "c"])
becomes
my Array[Str]() $a = ["a", "b", "c"];
say $a;
# OUTPUT: [a b c]
(That is, Array[Str]() means "something that can be coerced into an Array of Strings". That's different from Array[Str()] ("an Array of things that can be coerced to Strings") and from Array[Str()]() ("something that can be coerced into an Array of things that can be coerced into Strings").)
Similarly, the following part of the question now has an answer:
is there a single entry point used by the assignment operator which does all the coerce/typecheck? Ideally I would simply [define how a type is coerced into my type]
With the new coercion protocol, the "single entry point" is the COERCE method, which users can define for their types to teach Raku how to coerce into those types.

Enforcing method order in a Python module [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 last year.
Improve this question
What is the most Pythonic way to deal with a module in which methods must be called in a certain order?
As an example, I have an XML configuration that must be read before doing anything else because the configuration affects behavior.
The parse_config() must be called first with the configuration file provided. Calling other supporting methods, like query_data() won't work until parse_config() has been called.
I first implemented this as a singleton to ensure that a filename for the configuration is passed at the time of initialization, but I was noticing that modules are actually singletons. It's no longer a class, but just a regular module.
What's the best way to enforce the parse_config being called first in a module?
It is worth noting is that the function is actually parse_config(configfile).
If the object isn't valid before it's called, then call that method in __init__ (or use a factory function). You don't need any silly singletons, that's for sure.
The model I have been using is that subsequent functions are only available as methods on the return value of previous functions, like this:
class Second(object):
def two(self):
print "two"
return Third()
class Third(object):
def three(self):
print "three"
def one():
print "one"
return Second()
one().two().three()
Properly designed, this style (which I admit is not terribly Pythonic, yet) makes for fluent libraries to handle complex pipeline operations where later steps in the library require both the results of early calculations and fresh input from the calling function.
An interesting result is error handling. What I've found is the best way of handling well-understood errors in pipeline steps is having a blank Error class that supposedly can handle every function in the pipeline (except initial one) but those functions (except possibly terminal ones) return only self:
class Error(object):
def two(self, *args):
print "two not done because of earlier errors"
return self
def three(self, *args):
print "three not done because of earlier errors"
class Second(object):
def two(self, arg):
if arg == 2:
print "two"
return Third()
else:
print "two cannot be done"
return Error()
class Third(object):
def three(self):
print "three"
def one(arg):
if arg == 1:
print "one"
return Second()
else:
print "one cannot be done"
return Error()
one(1).two(-1).three()
In your example, you'd have the Parser class, which would have almost nothing but a configure function that returned an instance of a ConfiguredParser class, which would do all the thing that only a properly configured parser could do. This gives you access to such things as multiple configurations and handling failed attempts at configuration.
As Cat Plus Plus said in other words, wrap the behaviour/functions up in a class and put all the required setup in the __init__ method.
You might complain that the functions don't seem like they naturally belong together in an object and, hence, this is bad OO design. If that's the case, think of your class/object as a form of name-spacing. It's much cleaner and more flexible than trying to enforce function calling order somehow or using singletons.
The simple requirement that a module needs to be "configured" before it is used is best handled by a class which does the "configuration" in the __init__ method, as in the currently-accepted answer. Other module functions become methods of the class. There is no benefit in trying to make a singleton ... the caller may well want to have two or more differently-configured gadgets operating simultaneously.
Moving on from that to a more complicated requirement, such as a temporal ordering of the methods:
This can be handled in a quite general fashion by maintaining state in attributes of the object, as is usually done in any OOPable language. Each method that has prerequisites must check that those prequisites are satisfied.
Poking in replacement methods is an obfuscation on a par with the COBOL ALTER verb, and made worse by using decorators -- it just wouldn't/shouldn't get past code review.
It comes down to how friendly you want your error messages to be if a function is called before it is configured.
Least friendly is to do nothing extra, and let the functions fail noisily with AttributeErrors, IndexErrors, etc.
Most friendly would be having stub functions that raise an informative exception, such as a custom ConfigError: configuration not initialized. When the ConfigParser() function is called it can then replace the stub functions with real functions.
Something like this:
File config.py
class ConfigError(Exception):
"configuration errors"
def query_data():
raise ConfigError("parse_config() has not been called")
def _query_data():
do_actual_work()
def parse_config(config_file):
load_file(config_file)
if failure:
raise ConfigError("bad file")
all_objects = globals()
for name in ('query_data', ):
working_func = all_objects['_'+name]
all_objects[name] = working_func
If you have very many functions you can add decorators to keep track of the function names, but that's an answer for a different question. ;)
Okay, I couldn't resist -- here is the decorator version, which makes my solution much easier to actually implement:
class ConfigError(Exception):
"various configuration errors"
class NeedsConfig(object):
def __init__(self, module_namespace):
self._namespace = module_namespace
self._functions = dict()
def __call__(self, func):
self._functions[func.__name__] = func
return self._stub
#staticmethod
def _stub(*args, **kwargs):
raise ConfigError("parseconfig() needs to be called first")
def go_live(self):
for name, func in self._functions.items():
self._namespace[name] = func
And a sample run:
needs_parseconfig = NeedsConfig(globals())
#needs_parseconfig
def query_data():
print "got some data!"
#needs_parseconfig
def set_data():
print "set the data!"
def okay():
print "Okay!"
def parse_config(somefile):
needs_parseconfig.go_live()
try:
query_data()
except ConfigError, e:
print e
try:
set_data()
except ConfigError, e:
print e
try:
okay()
except:
print "this shouldn't happen!"
raise
parse_config('config_file')
query_data()
set_data()
okay()
And the results:
parseconfig() needs to be called first
parseconfig() needs to be called first
Okay!
got some data!
set the data!
Okay!
As you can see, the decorator works by remembering the functions it decorates, and instead of returning a decorated function it returns a simple stub that raises a ConfigError if it is ever called. When the parse_config() routine is called, it needs to call the go_live() method which will then replace all the error raising stubs with the actual remembered functions.
A module doesn't do anything it isn't told to do so put your function calls at the bottom of the module so that when you import it, things get ran in the order you specify:
test.py
import testmod
testmod.py
def fun1():
print('fun1')
def fun2():
print('fun2')
fun1()
fun2()
When you run test.py, you'll see fun1 is ran before fun2:
python test.py
fun1
fun2

Smalltalk exotic features

Smalltalk syntax (and features) can be found pretty exotic (and even disturbing) when you come from a more C-like syntax world. I found myself losing time with some
I would be interested in learning knowing what you found really exotic compared to more classic/mainstream languages and that you think helps to understand the language.
For example, evaluation with logic operators :
(object1 = object2) & (object3 = object4) : this will evaluate the whole expression, even if the left part is false, the rest will be evaluated.
(object1 = object2) and: [object3 = object4] : this will evaluate the left part, and only will evaluate the right part if the first is true.
Everything is an object, and everything above the VM's available for inspection and modification. (Primitives are part of the VM, conceptually at least.) Even your call stack's available (thisContext) - Seaside implemented continuations back in the day by simply swizzling down the call stack into a stream, and restoring it (returning to the continuation) by simply reading out activation frames from that stream!
You can construct a selector from a string and turn it into a Symbol and send it as a message: self perform: 'this', 'That' will do the same thing as self thisThat. (But don't do this, for the same reasons you should avoid eval in both Lisps and PHP: very hard to debug!)
Message passing: it's not method invocation!
#become: is probably a bit of a shock to anyone who hasn't seen it before. (tl;dr a wholesale swapping of two object pointers - all references to B now point to A, and all references to A now point to B)
Primitves
someMethod
<primitive 14122 wtf>
"fail and execute the following"
[self] inlineCopyInject: [:t1 | self].
My first wrestling session with Smalltalk was the metaclass implementation.
Consider this:
What is the class of 'This is a string'? Well, something like String.
What is the class of String? String class. Note: this is a class, but it has no name, it just prints itself as 'String class'.
What is the class of String class? Metaclass. Note: this is a named class.
What is the class of Metaclass? As you might expect (or not) this is Metaclass class. Of which, again as you might expect, the class is Metaclass again.
This is the first circularity. Another one which I found rather esoteric at first (of course, now I eat metaclasses for breakfast) is the next one:
What is the superclass of String? Object (eventually, different implementations of Smalltalk have different class hierarchies of these basic classes).
What is the superclass of Object? nil. Now this is an interesting answer in Smalltalk, because it actually is an object! nil class answers UndefinedObject. Of which the superclass is ... Object.
Navigating through the superclass and instance of relations was a real rollercoster ride for me in those days...
How about selective breakpointing (which I actually use at times):
foo
thisContext sender selector == #bar ifTrue:[ self halt ].
...
will debug itself, but only if called from bar. Useful, if foo is called for from zillion other places and a regular breakpoint hits too often.
I've always been fond of the Smalltalk quine:
quine
^thisContext method getSource
(Pharo version.)